﻿using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Windows.Input;
using WirelessAccessPoint.Core;
using WirelessAccessPoint.InteropServices;
using WirelessAccessPoint.Model;
using WirelessAccessPoint.Resources;
using WirelessAccessPoint.Services;

namespace WirelessAccessPoint
{
    /// <summary>
    /// WirelessAccessPointのViewModelです。
    /// </summary>
    public class WirelessAccessPointViewModel : ViewModelBase
    {
        private ObservableCollection<HostedNetworkPeer> hostedNetworkPeers;
        private ObservableCollection<NetSharing> netSharings;

        private HostedNetwork selectedHostedNetwork;
        private NetSharing selectedPublicNetSharing;

        private HostedNetwork activeHostedNetwork;
        private NetSharing activePublicNetSharing;
        private NetSharing activePrivateNetSharing;

        private string message;

        #region コンストラクタ

        /// <summary>
        /// このクラスの新しいインスタンスを初期化します。
        /// </summary>
        public WirelessAccessPointViewModel()
        {
            this.Update();
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            this.hostedNetworkPeers = null;
            this.netSharings = null;
            this.selectedHostedNetwork = null;
            this.selectedPublicNetSharing = null;
            this.activeHostedNetwork = null;
            this.activePublicNetSharing = null;
            this.activePrivateNetSharing = null;
        }

        #endregion

        #region プロパティ

        /// <summary>
        /// Hosted Networkに接続されているPeerの一覧を設定または取得します。
        /// </summary>
        public ObservableCollection<HostedNetworkPeer> HostedNetworkPeers
        {
            get { return this.hostedNetworkPeers; }
            set
            {
                if (value != this.hostedNetworkPeers)
                {
                    this.hostedNetworkPeers = value;
                    this.OnPropertyChanged(() => this.HostedNetworkPeers);
                }
            }
        }

        /// <summary>
        /// Internet Connection Sharing (ICS)一覧を設定または取得します。
        /// </summary>
        public ObservableCollection<NetSharing> NetSharings
        {
            get { return this.netSharings; }
            set
            {
                if (value != this.netSharings)
                {
                    this.netSharings = value;
                    this.OnPropertyChanged(() => this.NetSharings);
                }
            }
        }

        /// <summary>
        /// UIより入力中のHosted Networkを設定または取得します。
        /// </summary>
        public HostedNetwork SelectedHostedNetwork
        {
            get
            {
                if (this.selectedHostedNetwork == null)
                {
                    this.selectedHostedNetwork = new HostedNetwork();
                    this.OnPropertyChanged(() => this.SelectedHostedNetwork);
                }

                return this.selectedHostedNetwork;
            }
            set
            {
                if (value != this.selectedHostedNetwork)
                {
                    this.selectedHostedNetwork = value;
                    this.OnPropertyChanged(() => this.SelectedHostedNetwork);
                }
            }
        }

        /// <summary>
        /// UIより入力中のPublic側Internet Connection Sharing (ICS)を設定または取得します。
        /// </summary>
        [Display(ResourceType = typeof(LabelResource), Name = "SelectedPublicNetSharingLabel")]
        [Required(ErrorMessageResourceType = typeof(MessageResource), ErrorMessageResourceName = "RequiredMessage")]
        public NetSharing SelectedPublicNetSharing
        {
            get { return this.selectedPublicNetSharing; }
            set
            {
                if (value != this.selectedPublicNetSharing)
                {
                    this.selectedPublicNetSharing = value;
                    this.OnPropertyChanged(() => this.SelectedPublicNetSharing);
                }
            }
        }

        /// <summary>
        /// 開始しているHosted Networkを設定または取得します。
        /// </summary>
        public HostedNetwork ActiveHostedNetwork
        {
            get { return this.activeHostedNetwork; }
            set
            {
                if (value != this.activeHostedNetwork)
                {
                    this.activeHostedNetwork = value;
                    this.OnPropertyChanged(() => this.ActiveHostedNetwork);
                    this.OnPropertyChanged(() => this.IsActiveHostedNetworkAndNetSharing);
                }
            }
        }

        /// <summary>
        /// 開始しているPublic側Internet Connection Sharing (ICS)を設定または取得します。
        /// </summary>
        public NetSharing ActivePublicNetSharing
        {
            get { return this.activePublicNetSharing; }
            set
            {
                if (value != this.activePublicNetSharing)
                {
                    this.activePublicNetSharing = value;
                    this.OnPropertyChanged(() => this.ActivePublicNetSharing);
                    this.OnPropertyChanged(() => this.IsActiveHostedNetworkAndNetSharing);
                }
            }
        }

        /// <summary>
        /// 開始しているPrivate側Internet Connection Sharing (ICS)を設定または取得します。
        /// </summary>
        public NetSharing ActivePrivateNetSharing
        {
            get { return this.activePrivateNetSharing; }
            set
            {
                if (value != this.activePrivateNetSharing)
                {
                    this.activePrivateNetSharing = value;
                    this.OnPropertyChanged(() => this.ActivePrivateNetSharing);
                    this.OnPropertyChanged(() => this.IsActiveHostedNetworkAndNetSharing);
                }
            }
        }

        /// <summary>
        /// Hosted NetworkとInternet Connection Sharing (ICS)が開始中か停止中かを取得します。
        /// </summary>
        public bool IsActiveHostedNetworkAndNetSharing
        {
            get
            {
                return this.ActiveHostedNetwork != null
                    && this.ActiveHostedNetwork.HostedNetworkState == WLAN_HOSTED_NETWORK_STATE.wlan_hosted_network_active
                    && this.ActivePublicNetSharing != null
                    && this.ActivePublicNetSharing.SharingEnabled.GetValueOrDefault()
                    && this.ActivePrivateNetSharing != null
                    && this.ActivePrivateNetSharing.SharingEnabled.GetValueOrDefault();
            }
        }

        /// <summary>
        /// メッセージを設定または取得します。
        /// </summary>
        public string Message
        {
            get { return this.message; }
            set
            {
                if (value != this.message)
                {
                    this.message = value;
                    this.OnPropertyChanged(() => this.Message);
                }
            }
        }

        #endregion

        #region コマンド

        /// <summary>
        /// Hosted NetworkとInternet Connection Sharing (ICS)を開始または停止します。
        /// </summary>
        private RelayCommand startOrStopCommand;
        public ICommand StartOrStopCommand
        {
            get
            {
                if (this.startOrStopCommand == null)
                {
                    this.startOrStopCommand = new RelayCommand(p => this.StartOrStop(), p => this.CanStartStop());
                }

                return this.startOrStopCommand;
            }
        }

        /// <summary>
        /// Hosted NetworkとInternet Connection Sharing (ICS)の状態を更新します。
        /// </summary>
        private RelayCommand updateCommand;
        public ICommand UpdateCommand
        {
            get
            {
                if (this.updateCommand == null)
                {
                    this.updateCommand = new RelayCommand(p => this.Update());
                }

                return this.updateCommand;
            }
        }

        #endregion

        #region メソッド

        /// <summary>
        /// Hosted NetworkとInternet Connection Sharing (ICS)を開始または停止します。
        /// </summary>
        private void StartOrStop()
        {
            this.TaskStart(() =>
            {
                var netSharingService = new NetSharingService();
                var hostedNetworkService = new HostedNetworkService();

                if (this.IsActiveHostedNetworkAndNetSharing)
                {
                    this.DispatcherInvoke(() => this.Message = MessageResource.StopNetSharingMessage);
                    netSharingService.Disable();
                    Thread.Sleep(500);
                    var netSharingContext = netSharingService.Update(this.SelectedPublicNetSharing);
                    this.DispatcherInvoke(() =>
                    {
                        this.NetSharings = netSharingContext.NetSharings;
                        this.SelectedPublicNetSharing = netSharingContext.SelectedPublicNetSharing;
                        this.ActivePublicNetSharing = netSharingContext.ActivePublicNetSharing;
                        this.ActivePrivateNetSharing = netSharingContext.ActivePrivateNetSharing;
                    });

                    this.DispatcherInvoke(() => this.Message = MessageResource.StopHostedNetworkMessage);
                    hostedNetworkService.Disable();
                    Thread.Sleep(500);
                    var hostedNetworkContext = hostedNetworkService.Update(this.SelectedHostedNetwork);
                    this.DispatcherInvoke(() =>
                    {
                        this.HostedNetworkPeers = hostedNetworkContext.HostedNetworkPeers;
                        this.SelectedHostedNetwork = hostedNetworkContext.SelectedHostedNetwork;
                        this.ActiveHostedNetwork = hostedNetworkContext.ActiveHostedNetwork;
                    });
                }
                else
                {
                    this.DispatcherInvoke(() => this.Message = MessageResource.StartHostedNetworkMessage);
                    hostedNetworkService.Enable(this.SelectedHostedNetwork);
                    Thread.Sleep(500);
                    var hostedNetworkContext = hostedNetworkService.Update(this.SelectedHostedNetwork);
                    this.DispatcherInvoke(() =>
                    {
                        this.HostedNetworkPeers = hostedNetworkContext.HostedNetworkPeers;
                        this.SelectedHostedNetwork = hostedNetworkContext.SelectedHostedNetwork;
                        this.ActiveHostedNetwork = hostedNetworkContext.ActiveHostedNetwork;
                    });

                    this.DispatcherInvoke(() => this.Message = MessageResource.StartNetSharingMessage);
                    netSharingService.Enable(this.ActiveHostedNetwork, this.SelectedPublicNetSharing);
                    Thread.Sleep(500);
                    var netSharingContext = netSharingService.Update(this.SelectedPublicNetSharing);
                    this.DispatcherInvoke(() =>
                    {
                        this.NetSharings = netSharingContext.NetSharings;
                        this.SelectedPublicNetSharing = netSharingContext.SelectedPublicNetSharing;
                        this.ActivePublicNetSharing = netSharingContext.ActivePublicNetSharing;
                        this.ActivePrivateNetSharing = netSharingContext.ActivePrivateNetSharing;
                    });
                }
            });
        }

        /// <summary>
        /// Hosted NetworkとInternet Connection Sharing (ICS)を開始または停止できるかどうかを取得します。
        /// </summary>
        private bool CanStartStop()
        {
            return this.SelectedHostedNetwork != null
                && string.IsNullOrEmpty(this.SelectedHostedNetwork.Error)
                && string.IsNullOrEmpty(this.Error);
        }

        /// <summary>
        /// Hosted NetworkとInternet Connection Sharing (ICS)の状態を更新します。
        /// </summary>
        private void Update()
        {
            this.TaskStart(() =>
            {
                this.DispatcherInvoke(() => this.Message = MessageResource.UpdateHostedNetworkMessage);
                var hostedNetworkService = new HostedNetworkService();
                var hostedNetworkContext = hostedNetworkService.Update(this.SelectedHostedNetwork);
                this.DispatcherInvoke(() =>
                {
                    this.HostedNetworkPeers = hostedNetworkContext.HostedNetworkPeers;
                    this.SelectedHostedNetwork = hostedNetworkContext.SelectedHostedNetwork;
                    this.ActiveHostedNetwork = hostedNetworkContext.ActiveHostedNetwork;
                });

                this.DispatcherInvoke(() => this.Message = MessageResource.UpdateNetSharingMessage);
                var netSharingService = new NetSharingService();
                var netSharingContext = netSharingService.Update(this.SelectedPublicNetSharing);
                this.DispatcherInvoke(() =>
                {
                    this.NetSharings = netSharingContext.NetSharings;
                    this.SelectedPublicNetSharing = netSharingContext.SelectedPublicNetSharing;
                    this.ActivePublicNetSharing = netSharingContext.ActivePublicNetSharing;
                    this.ActivePrivateNetSharing = netSharingContext.ActivePrivateNetSharing;
                });
            });
        }

        #endregion
    }
}
